package com.java.simple.study.juc.pattern;

import com.java.simple.study.tool.Sleeper;
import lombok.extern.slf4j.Slf4j;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author zhoujl
 * @date 2022/5/9 16:33
 * @desc
 */
@Slf4j(topic = "c.TestGuardedObject")
public class TestGuardedObjectV3 {

    public static void main(String[] args) {
        for (int i = 0; i < 3; i++) {
            new People().start();
        }
        Sleeper.sleep(1);
        for (Integer id : Features.getIds()) {
            new Postman(id, "内容：" + id).start();
        }
    }


}

class GuardedObjectV3 {
    // 标识  可以被多个线程使用
    private int id;
    private Object response;

    public GuardedObjectV3(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public Object get(long mills) {
        synchronized (this) {
            // 1. 记录最初时间
            long begin = System.currentTimeMillis();
            // 2. 已经经历的时间
            long timePassed = 0;
            while (response == null) {
                // 4. 假设mills是1000 结果在400时唤醒了，那么还有600要等
                long waitTime = mills - timePassed;
                if (waitTime <= 0) {
                    break;
                }
                try {
                    this.wait(waitTime);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 3. 如果提前被唤醒 这时已经经历的时间为400
                timePassed = System.currentTimeMillis() - begin;
            }
            return response;
        }
    }

    public void complete(Object response) {
        synchronized (this) {
            this.response = response;
            this.notifyAll();
        }
    }

}

class Features {
    private static Map<Integer, GuardedObjectV3> FEATURES = new ConcurrentHashMap<>();
    private static int id = 1;

    private static synchronized int generateId() {
        return id++;
    }

    public static GuardedObjectV3 getGuardedObject(int id) {
        return FEATURES.remove(id);
    }

    public static GuardedObjectV3 createGuardedObject() {
        GuardedObjectV3 guardedObjectV3 = new GuardedObjectV3(generateId());
        FEATURES.put(guardedObjectV3.getId(), guardedObjectV3);
        return guardedObjectV3;
    }

    public static Set<Integer> getIds() {
        return FEATURES.keySet();
    }

}

@Slf4j(topic = "c.People")
class People extends Thread {
    @Override
    public void run() {
        GuardedObjectV3 guardedObject = Features.createGuardedObject();
        log.debug("开始收信 id:{}", guardedObject.getId());
        Object text = guardedObject.get(5000);
        log.debug("收到信 id:{}, 内容:{}", guardedObject.getId(), text);
    }
}

@Slf4j(topic = "c.Postman")
class Postman extends Thread {
    private int id;
    private String text;

    public Postman(int id, String text) {
        this.id = id;
        this.text = text;
    }

    @Override
    public void run() {
        GuardedObjectV3 guardedObject = Features.getGuardedObject(id);
        log.debug("送信id:{},内容：{}", id, text);
        guardedObject.complete(guardedObject);
    }
}

